#!/bin/bash

# 资产管理系统 - 零停机更新脚本
# 版本: 1.0

set -e

# 颜色定义
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'

# 配置变量
APP_DIR="/opt/asset-management"
BACKUP_DIR="/opt/asset_backups"
UPDATE_DIR="/tmp/asset_update_$(date +%s)"

# 日志函数
log_info() {
    echo -e "${BLUE}[INFO]${NC} $1"
}

log_success() {
    echo -e "${GREEN}[SUCCESS]${NC} $1"
}

log_warning() {
    echo -e "${YELLOW}[WARNING]${NC} $1"
}

log_error() {
    echo -e "${RED}[ERROR]${NC} $1"
}

# 显示使用方法
show_usage() {
    echo "使用方法: $0 [选项]"
    echo "选项:"
    echo "  -s, --source <path>    指定更新源路径（本地目录或Git仓库）"
    echo "  -b, --branch <branch>  指定Git分支（默认: main）"
    echo "  -f, --force           强制更新（跳过确认）"
    echo "  -h, --help            显示帮助信息"
    echo
    echo "示例:"
    echo "  $0 -s /path/to/new/code"
    echo "  $0 -s https://github.com/user/repo.git -b release"
}

# 解析参数
parse_arguments() {
    SOURCE=""
    BRANCH="main"
    FORCE=false
    
    while [[ $# -gt 0 ]]; do
        case $1 in
            -s|--source)
                SOURCE="$2"
                shift 2
                ;;
            -b|--branch)
                BRANCH="$2"
                shift 2
                ;;
            -f|--force)
                FORCE=true
                shift
                ;;
            -h|--help)
                show_usage
                exit 0
                ;;
            *)
                log_error "未知参数: $1"
                show_usage
                exit 1
                ;;
        esac
    done
    
    if [[ -z "$SOURCE" ]]; then
        log_error "必须指定更新源"
        show_usage
        exit 1
    fi
}

# 检查环境
check_environment() {
    log_info "检查环境..."
    
    if [[ ! -d "$APP_DIR" ]]; then
        log_error "应用目录不存在: $APP_DIR"
        exit 1
    fi
    
    cd "$APP_DIR"
    
    # 检查Docker服务
    if ! docker-compose ps >/dev/null 2>&1; then
        log_error "Docker服务未运行或配置错误"
        exit 1
    fi
    
    log_success "环境检查通过"
}

# 创建更新前备份
create_pre_update_backup() {
    log_info "创建更新前备份..."
    
    local backup_script="$APP_DIR/scripts/maintenance/backup.sh"
    
    if [[ -f "$backup_script" ]]; then
        bash "$backup_script"
        log_success "更新前备份完成"
    else
        log_warning "备份脚本不存在，跳过备份"
    fi
}

# 获取更新源
get_update_source() {
    log_info "获取更新源..."
    
    mkdir -p "$UPDATE_DIR"
    
    if [[ -d "$SOURCE" ]]; then
        # 本地目录
        log_info "从本地目录复制: $SOURCE"
        cp -r "$SOURCE"/* "$UPDATE_DIR/"
    elif [[ "$SOURCE" =~ ^https?:// ]] || [[ "$SOURCE" =~ \.git$ ]]; then
        # Git仓库
        log_info "从Git仓库克隆: $SOURCE (分支: $BRANCH)"
        git clone -b "$BRANCH" "$SOURCE" "$UPDATE_DIR"
    else
        log_error "不支持的更新源格式: $SOURCE"
        exit 1
    fi
    
    log_success "更新源获取完成"
}

# 检查更新内容
check_update_content() {
    log_info "检查更新内容..."
    
    # 检查必要文件
    local required_files=("manage.py" "requirements.txt" "docker-compose.yml")
    
    for file in "${required_files[@]}"; do
        if [[ ! -f "$UPDATE_DIR/$file" ]]; then
            log_error "更新源缺少必要文件: $file"
            exit 1
        fi
    done
    
    # 比较版本信息
    if [[ -f "$UPDATE_DIR/VERSION" && -f "$APP_DIR/VERSION" ]]; then
        local current_version=$(cat "$APP_DIR/VERSION" 2>/dev/null || echo "unknown")
        local new_version=$(cat "$UPDATE_DIR/VERSION" 2>/dev/null || echo "unknown")
        
        log_info "当前版本: $current_version"
        log_info "新版本: $new_version"
    fi
    
    log_success "更新内容检查通过"
}

# 确认更新操作
confirm_update() {
    if [[ "$FORCE" == "true" ]]; then
        return 0
    fi
    
    log_warning "即将执行系统更新操作"
    log_warning "更新源: $SOURCE"
    log_warning "更新时间: $(date)"
    echo
    read -p "确定要继续更新操作吗？(y/N): " confirmation
    
    if [[ ! "$confirmation" =~ ^[Yy]$ ]]; then
        log_info "更新操作已取消"
        exit 0
    fi
}

# 检查依赖变化
check_dependencies() {
    log_info "检查依赖变化..."
    
    if [[ -f "$UPDATE_DIR/requirements.txt" ]]; then
        if ! diff -q "$APP_DIR/requirements.txt" "$UPDATE_DIR/requirements.txt" >/dev/null 2>&1; then
            log_info "检测到Python依赖变化，需要重新构建镜像"
            REBUILD_IMAGE=true
        else
            REBUILD_IMAGE=false
        fi
    fi
    
    if [[ -f "$UPDATE_DIR/docker-compose.yml" ]]; then
        if ! diff -q "$APP_DIR/docker-compose.yml" "$UPDATE_DIR/docker-compose.yml" >/dev/null 2>&1; then
            log_info "检测到Docker配置变化"
            CONFIG_CHANGED=true
        else
            CONFIG_CHANGED=false
        fi
    fi
}

# 执行数据库迁移（如果需要）
run_migrations() {
    log_info "检查数据库迁移..."
    
    # 创建临时容器执行迁移检查
    local temp_container="asset_migration_check"
    
    # 构建临时镜像
    docker build -t asset_temp "$UPDATE_DIR"
    
    # 运行迁移检查
    docker run --rm --name "$temp_container" \
        --network "$(docker-compose ps -q web | xargs docker inspect --format='{{range .NetworkSettings.Networks}}{{.NetworkID}}{{end}}' | head -1)" \
        -e DB_HOST=asset_db \
        -e DB_PORT=3306 \
        -e DB_NAME=asset_db \
        -e DB_USER=root \
        -e DB_PASSWORD=123456 \
        asset_temp python manage.py showmigrations --plan > /tmp/migration_plan.txt
    
    if grep -q "[ ]" /tmp/migration_plan.txt; then
        log_info "发现待执行的数据库迁移"
        NEED_MIGRATION=true
    else
        log_info "无需执行数据库迁移"
        NEED_MIGRATION=false
    fi
    
    # 清理临时镜像
    docker rmi asset_temp
}

# 执行蓝绿部署
blue_green_deployment() {
    log_info "开始蓝绿部署..."
    
    # 复制新代码到应用目录
    log_info "更新应用代码..."
    rsync -av --exclude='.env' --exclude='logs/' "$UPDATE_DIR/" "$APP_DIR/"
    
    # 重新构建镜像（如果需要）
    if [[ "$REBUILD_IMAGE" == "true" ]]; then
        log_info "重新构建应用镜像..."
        docker-compose build --no-cache web
    fi
    
    # 执行数据库迁移（如果需要）
    if [[ "$NEED_MIGRATION" == "true" ]]; then
        log_info "执行数据库迁移..."
        docker-compose exec -T web python manage.py migrate
    fi
    
    # 收集静态文件
    log_info "收集静态文件..."
    docker-compose exec -T web python manage.py collectstatic --noinput
    
    # 滚动重启服务
    log_info "滚动重启服务..."
    
    # 重启Celery服务
    docker-compose restart celery celery-beat
    
    # 重启Web服务（逐个重启以保证服务可用性）
    if docker-compose ps | grep -q "asset_web"; then
        docker-compose up -d --scale web=2 web
        sleep 30
        docker-compose up -d --scale web=1 web
    else
        docker-compose up -d web
    fi
    
    # 重启Nginx
    docker-compose restart nginx
    
    log_success "蓝绿部署完成"
}

# 健康检查
health_check() {
    log_info "执行健康检查..."
    
    local max_attempts=20
    local attempt=1
    
    while [[ $attempt -le $max_attempts ]]; do
        if curl -s -o /dev/null -w "%{http_code}" http://localhost/health/ | grep -q "200"; then
            log_success "健康检查通过"
            return 0
        fi
        
        log_info "等待服务启动... ($attempt/$max_attempts)"
        sleep 15
        ((attempt++))
    done
    
    log_error "健康检查失败"
    return 1
}

# 回滚操作
rollback() {
    log_warning "更新失败，开始回滚..."
    
    # 查找最新的备份
    local latest_backup=$(ls -t "$BACKUP_DIR"/backup_*.tar.gz 2>/dev/null | head -1)
    
    if [[ -n "$latest_backup" ]]; then
        log_info "使用备份文件回滚: $latest_backup"
        bash "$APP_DIR/scripts/maintenance/restore.sh" "$latest_backup"
    else
        log_error "没有找到备份文件，无法自动回滚"
        log_error "请手动检查系统状态"
    fi
}

# 清理临时文件
cleanup() {
    log_info "清理临时文件..."
    
    if [[ -d "$UPDATE_DIR" ]]; then
        rm -rf "$UPDATE_DIR"
    fi
    
    # 清理临时镜像
    docker image prune -f >/dev/null 2>&1 || true
    
    log_success "临时文件清理完成"
}

# 显示更新信息
show_update_info() {
    log_success "=== 系统更新完成 ==="
    echo
    log_info "更新信息:"
    log_info "  更新源: $SOURCE"
    log_info "  更新时间: $(date)"
    echo
    log_info "服务状态:"
    docker-compose ps
    echo
    log_info "建议操作:"
    log_info "1. 检查应用功能是否正常"
    log_info "2. 查看应用日志: docker-compose logs -f"
    log_info "3. 监控系统性能"
}

# 错误处理
error_handler() {
    log_error "更新过程中发生错误"
    
    # 尝试回滚
    rollback
    
    # 清理临时文件
    cleanup
    
    exit 1
}

# 主函数
main() {
    log_info "开始执行系统更新..."
    log_info "更新时间: $(date)"
    
    # 设置错误处理
    trap error_handler ERR
    
    parse_arguments "$@"
    check_environment
    create_pre_update_backup
    get_update_source
    check_update_content
    confirm_update
    check_dependencies
    run_migrations
    blue_green_deployment
    
    if health_check; then
        cleanup
        show_update_info
        log_success "系统更新完成！"
    else
        log_error "更新后健康检查失败"
        rollback
        exit 1
    fi
}

# 执行主函数
main "$@"